package com.gitee.wsl.compose.modifier.draw

import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection

fun Modifier.fadingEdge(
    left: Dp? = null,
    top: Dp? = null,
    right: Dp? = null,
    bottom: Dp? = null,
) = graphicsLayer(alpha = EdgeAlpha)
    .drawWithContent {
        drawContent()
        if (top != null) {
            drawRect(
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color.Transparent,
                        Color.Black
                    ),
                    startY = 0f,
                    endY = top.toPx()
                ),
                blendMode = BlendMode.DstIn
            )
        }
        if (bottom != null) {
            drawRect(
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color.Black,
                        Color.Transparent
                    ),
                    startY = size.height - bottom.toPx(),
                    endY = size.height
                ),
                blendMode = BlendMode.DstIn
            )
        }
        if (left != null) {
            drawRect(
                brush = Brush.horizontalGradient(
                    colors = listOf(
                        Color.Black,
                        Color.Transparent
                    ),
                    startX = 0f,
                    endX = left.toPx()
                ),
                blendMode = BlendMode.DstIn
            )
        }
        if (right != null) {
            drawRect(
                brush = Brush.horizontalGradient(
                    colors = listOf(
                        Color.Transparent,
                        Color.Black
                    ),
                    startX = size.width - right.toPx(),
                    endX = size.width
                ),
                blendMode = BlendMode.DstIn
            )
        }
    }

fun Modifier.fadingEdge(
    horizontal: Dp? = null,
    vertical: Dp? = null,
) = fadingEdge(
    left = horizontal,
    right = horizontal,
    top = vertical,
    bottom = vertical
)


/**
 * The edge to use with [fadingEdge] modifier.
 */
@Suppress("UndocumentedPublicProperty") // what's here to document?
enum class FadingEdge {
    Start, End, Top, Bottom
}

private const val EdgeAlpha = 0.99f

/**
 * Makes this widget "fade out" into transparency over specified [size].
 * The edge specified by [fadingEdge] will be faded only.
 *
 * For RTL layouts, if [rtlAware] is true, automatically inverts the fading edge direction.
 */
fun Modifier.fadingEdge(
    fadingEdge: FadingEdge,
    size: Dp,
    rtlAware: Boolean = false,
): Modifier = composed {
    val direction = LocalLayoutDirection.current
    val invert = direction == LayoutDirection.Rtl && rtlAware
    val edge = when (fadingEdge) {
        FadingEdge.Top, FadingEdge.Bottom -> fadingEdge
        FadingEdge.Start -> if (invert) FadingEdge.End else FadingEdge.Start
        FadingEdge.End -> if (invert) FadingEdge.Start else FadingEdge.End
    }
    graphicsLayer { alpha = EdgeAlpha }.drawWithCache {
        val colors = listOf(Color.Transparent, Color.Black)
        val sizePx = size.toPx()
        val brush = when (edge) {
            FadingEdge.Start -> Brush.horizontalGradient(colors, startX = 0f, endX = sizePx)
            FadingEdge.End -> Brush.horizontalGradient(
                colors.reversed(),
                startX = this.size.width - sizePx,
                endX = this.size.width
            )

            FadingEdge.Top -> Brush.verticalGradient(colors, startY = 0f, endY = sizePx)
            FadingEdge.Bottom -> Brush.verticalGradient(
                colors.reversed(),
                startY = this.size.height - sizePx,
                endY = this.size.height
            )
        }
        onDrawWithContent {
            drawContent()
            drawRect(
                brush = brush,
                blendMode = BlendMode.DstIn
            )
        }
    }
}
